package com.egoonet.websocket;

import java.io.IOException;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.egoonet.pojo.JoinResult;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;

@ServerEndpoint(value="/msgserver")
public class MsgServerWSEndpoint {
	private final Logger logger = LoggerFactory.getLogger(MsgServerWSEndpoint.class);
	private Session session;
	private WSConnInfo connInfo;
	
	@OnOpen
	public void start(Session session){
		logger.debug("收到新的WebSocket连接请求[{}]", session);
		this.session = session;
	}
	
	@OnClose
	public void end(){
		logger.debug("收到关闭WebSocket的请求[{}]", connInfo);
		WebSocketServer.delConnection(this);
	}
	
	@OnError
	public void onError(Session session, Throwable error){
		String info = "";
		if(connInfo!=null){
			info = "userid[" + connInfo.getUserId() + "]" + error.getMessage();
		}
		logger.warn("WebSocket连接出现异常" + info);
		WebSocketServer.delConnection(this);
	}
	
	@OnMessage
	public void receive(String message){
		logger.debug("收到客户端发来的消息[{}]", message);
		String rtMsg = null;

		try {
			JSONObject json = new JSONObject(message);
			Preconditions.checkNotNull(json, "message not valid json format");

			String eventName = json.getString("eventName");
			Preconditions.checkArgument(!Strings.isNullOrEmpty(eventName), "miss eventName header");
			
			JSONObject data = json.getJSONObject("data");
			Preconditions.checkNotNull(data, "null data");
			if(eventName.equals("__join")){
				JoinResult result = handleJoin(data);
				if(!result.isSucc()){
					easySendMsg(result.getMsg());
					closeSession();
				}else{
					easySendMsg(result.getMsg());
				}
			}else if(eventName.equals("__lockuser")){
				rtMsg = handleLockUser(data);
				easySendMsg(rtMsg);
			}else if(eventName.equals("__unlockuser")){
				rtMsg = handleUnlockUser(data);
				easySendMsg(rtMsg);
			}else{
				logger.warn("未知的消息类型[{}]", eventName);
			}
		} catch (Exception e) {
			logger.warn("处理收到的消息发生异常", e);
		}
	}
	
	/**
	 * 解锁用户
	 * @param data
	 * @return
	 */
	private String handleUnlockUser(JSONObject data) {
		logger.debug("开始解锁用户[{}]", data);
		boolean isSucc = false;
		String msg = null;
		if(connInfo!=null){
			connInfo.setLocked(false);
			isSucc = true;
		}else{
			msg = "no such user";
			logger.warn("解锁用户失败，因connInfo为空");
		}

		return MsgHelper.buildUnlockResult(isSucc, msg);
	}

	/**
	 * 锁定用户，避免用户重复登录
	 * @param data
	 * @return
	 */
	private String handleLockUser(JSONObject data) {
		logger.debug("开始锁定用户[{}}", data);
		boolean isSucc = false;
		String msg = null;
		if(connInfo!=null){
			connInfo.setLocked(true);
			isSucc = true;
		}else{
			msg = "no such user";
			logger.warn("锁定用户失败，因connInfo为空");
		}

		return MsgHelper.buildLockResult(isSucc, msg);
	}

	/**
	 * 处理用户WebSocket连接请求
	 * @param data
	 */
	private JoinResult handleJoin(JSONObject data) {
		JoinResult result = new JoinResult();
		result.setSucc(false);

		String rtMsg;
		String userId = data.getString("userId");
		String roomId = data.getString("room");
		
		String endpointType = null;
		try{
			endpointType = data.getString("endpointType"); //终端类型
		}catch(Exception ex){
			logger.debug("json消息中没有endpointType");
		}

		connInfo = new WSConnInfo();
		connInfo.setRoomId(roomId);
		connInfo.setUserId(userId);
		connInfo.setEndpointType(endpointType);
	
		Preconditions.checkArgument(!Strings.isNullOrEmpty(userId), "null userId");
		
		//如果该用户id已经被登录，则发送强制退出消息，并关闭WebSocket连接
		MsgServerWSEndpoint oldEndpoint = WebSocketServer.getEndpointByUserId(userId);
		if(oldEndpoint != null ){
			if(oldEndpoint.getConnInfo().isLocked()){
				logger.debug("用户[{}]已经被锁定，不允许再次登录, 需要关闭当前的WebSocket连接", userId);
				rtMsg = MsgHelper.buildLoginResult(false, "user account locked");
				result.setMsg(rtMsg);
				return result;
			}else{
				logger.debug("该用户[{}]已在其它地方登录", userId);
				rtMsg = MsgHelper.buildForceLogoutResult("user has new login");
				oldEndpoint.easySendMsg(rtMsg);
				oldEndpoint.closeSession();
			}
		}
		
		logger.debug("收到WebSocket的入会请求[{}]", connInfo);
		WebSocketServer.addConnection(this);

		rtMsg = MsgHelper.buildLoginResult(true, null);
		result.setSucc(true);
		result.setMsg(rtMsg);
		return result;
	}

	/**
	 * 返回结果信息
	 * @param isSucc
	 * @param msg
	 * @return
	 */
	public String buildRetMsg(boolean isSucc, String msg){
		JSONObject json = new JSONObject();
		json.put("result", isSucc);
		json.put("msg", msg);
		return json.toString();
	}
	
	/**
	 * 发送消息的简化版本，不会提示警告
	 * @param msg
	 */
	private void easySendMsg(String msg){
		try {
			logger.debug("开始发送消息[{}]", msg);
			sendMsg(msg);
		} catch (IOException e) {
			logger.warn("发送websocket返回消息出现异常", e);
		}
	}
	
	public boolean sendMsg(String msg) throws IOException{
		Preconditions.checkNotNull(session, "session is null");
		Preconditions.checkState(session.isOpen(), "session is closed");
		session.getBasicRemote().sendText(msg);
		
		return true;
	}
	
	/**
	 * 关闭WebSocket连接
	 */
	public void closeSession(){
		try {
			session.close();
		} catch (IOException e) {
			logger.warn("关闭WebSocket出现异常", e);
		}
	}

	public Session getSession() {
		return session;
	}

	public WSConnInfo getConnInfo() {
		return connInfo;
	}
}
